<?php


namespace App\Services;

use Illuminate\Support\Facades\DB;

/**
 * 安装服务
 * Class InstallService
 * @package App\Services
 */
class InstallService
{
    // 修改或添加env文件
    public function writeEnv($data)
    {
        $envPath = base_path(".env");
        $envExamplePath = base_path(".env.example");

        if (file_exists($envPath)) {  // 如果存在.env文件 或者 .env.example文件
            $filePointer = fopen($envPath, "r");
            // 把整个文件读取内存中
            $str = fread($filePointer, filesize($envPath));
            // 在内存中修改.env的内容
            $str = $this->envReplace("DB_HOST", $data["DB_HOST"], $str);
            $str = $this->envReplace("DB_DATABASE", $data["DB_DATABASE"], $str);
            $str = $this->envReplace("DB_USERNAME", $data["DB_USERNAME"], $str);
            $str = $this->envReplace("DB_PASSWORD", $data["DB_PASSWORD"], $str);
            $str = $this->envReplace("DB_PORT", $data["DB_PORT"], $str);
            $str = $this->envReplace("QUEUE_CONNECTION", "sync", $str);  // 这里不使用redis
            $str = $this->envReplace("REDIS_HOST", $data["REDIS_HOST"], $str);
            $str = $this->envReplace("REDIS_PASSWORD", $data["REDIS_PASSWORD"], $str);
            $str = $this->envReplace("REDIS_PORT", $data["REDIS_PORT"], $str);
            fclose($filePointer); // 读取完毕

            // 写入到.env
            $filePointerWrite = fopen($envPath, "w");
            fwrite($filePointerWrite, $str);
            fclose($filePointerWrite);

        } else if (!file_exists($envPath) && file_exists($envExamplePath)) {

            $filePointer = fopen($envExamplePath, "r");
            // 把整个文件读取内存中
            $str = fread($filePointer, filesize($envExamplePath));
            // 在内存中修改.env的内容
            $str = $this->envReplace("DB_HOST", $data["DB_HOST"], $str);
            $str = $this->envReplace("DB_DATABASE", $data["DB_DATABASE"], $str);
            $str = $this->envReplace("DB_USERNAME", $data["DB_USERNAME"], $str);
            $str = $this->envReplace("DB_PASSWORD", $data["DB_PASSWORD"], $str);
            $str = $this->envReplace("DB_PORT", $data["DB_PORT"], $str);
            fclose($filePointer); // 读取完毕

            // 写入到.env
            $filePointerWrite = fopen($envPath, "w+");
            fwrite($filePointerWrite, $str);
            fclose($filePointerWrite);
        } else {
            throw new \RuntimeException(".env文件和.env.example文件不存在");
        }
    }

    // 动态修改env文件的某个参数
    public function editEnv($env_name, $replacement)
    {
        $envPath = base_path(".env");
        if (file_exists($envPath)) {
            $filePointer = fopen($envPath, "r");
            $str = fread($filePointer, filesize($envPath));
            fclose($filePointer); // 读取完毕
            // 写入到.env
            $filePointerWrite = fopen($envPath, "w");
            $str = $this->envReplace($env_name, $replacement, $str);
            fwrite($filePointerWrite, $str);
            fclose($filePointerWrite);
        }else {
            throw new \RuntimeException(".env文件");
        }
    }

    // 修改.env文件里面的内容
    private function envReplace($env_name, $replacement, $str)
    {
        return preg_replace("/({$env_name}=(\w|.)+\s|{$env_name}=\s)/", "{$env_name}={$replacement}\n", $str);
    }

    // 测试数据库连接
    public function checkSqlConnection()
    {
        $DB_HOST = env('DB_HOST');
        $DB_USERNAME = env('DB_USERNAME');
        $DB_PASSWORD = env('DB_PASSWORD');

        $dns = "mysql:host={$DB_HOST};";
        try {
            // 使用pdo连接数据库进行测试
            $link = new \PDO($dns, $DB_USERNAME, $DB_PASSWORD); // 连接数据库
            $link->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
        } catch (\PDOException $e) {
            // 连接失败
            $link = null;
            return false;
        }

        $link = null;
        return true;
    }

    // 检测是否安装成功
    public function isInstall()
    {
        // 通过判断是否存在admin_users表来判断是否安装, 同时判断该表是否有字段. 如果有则表示安装成功, 否则都是失败
        try {
            $admin = DB::table('admin_users')->first();
        } catch (\Exception $e) {
            return false;
        }

        if (!$admin) {
            return false;
        }

        return true;
    }


    // 检查环境变量
    public function checkEnv()
    {
        $envArray = [
            'os' => ["操作系统", "无限制", "linux", PHP_OS, 'success'],
            'php' => ['PHP版本', "7.2", "7.3", PHP_VERSION, 'success'],
            'gd' => ['GD库', "2.0", "2.0", '未知', 'success'],
            'upload' => ['附件上传', "无限制", "2M", '未知', 'success'],
            'disk' => ['磁盘空间', "200M", ">100M", '未知', 'success'],
        ];

        // 检测附件上传
        if (@ini_get('file_uploads')) {
            $envArray['upload'][3] = ini_get("upload_max_filesize");
        }

        // 获取磁盘空间
        if (function_exists("disk_free_space")) {
            $envArray['disk'][3] = floor(disk_free_space(__DIR__) / (1024 * 1024)) . "M";
        }

        // 检测gd库
        $gdArr = function_exists("gd_info") ? gd_info() : [];
        if (empty($gdArr)) {
            $envArray['gd'][3] = "未安装";
            $envArray['gd'][4] = "error";
            session(['install.error' => true]);
        } else {
            $envArray['gd'][3] = $gdArr["GD Version"];
        }
        unset($gdArr);

        return $envArray;
    }

    // 检查函数
    public function checkFunction()
    {
        $functionArray = [
            ["fsockopen", "支持", "支持", "success"],
            ["gethostbyname", "支持", "支持", "success"],
            ["file_get_contents", "支持", "支持", "success"],
            ["mb_convert_encoding", "支持", "支持", "success"],
            ["json_encode", "支持", "支持", "success"]
        ];

        foreach ($functionArray as $key => $value) {
            if (!function_exists($value[0])) {
                session(['install.error' => true]);
                $functionArray[$key][2] = "不支持";
                $functionArray[$key][3] = "error";
            }
        }

        return $functionArray;
    }

    // 检查目录和文件是否可以写入
    public function checkDirAndFile() {
        $dirAndFile = [
            ['dir', '可写', '可写', 'storage', 'success'],
            ['dir', '可写', '可写', 'public/storage', 'success'],
            ['file', '可写', '可写', 'database/admin.sql', 'success'],
            ['file', '可写', '可写', '.env', 'success']
        ];

        foreach ($dirAndFile as $k => $v) {
            $path = base_path($v[3]);
            if ($v[0] == 'dir') {  // 如果是目录
                if (!is_writable($path)) {
                    if (is_dir($path)) {
                        $dirAndFile[$k][2] = "不可写";
                        $dirAndFile[$k][1] = "不可写";
                        $dirAndFile[$k][4] = "error";
                        session(['install.error' => true]);
                    } else {
                        $dirAndFile[$k][2] = "不存在";
                        $dirAndFile[$k][1] = "不存在";
                        $dirAndFile[$k][4] = "error";
                        session(['install.error' => true]);
                    }
                }
            } else {  // 如果是文件
                if (!is_writable($path)) {
                    if (file_exists($path)) {
                        $dirAndFile[$k][2] = "不可写";
                        $dirAndFile[$k][1] = "不可写";
                        $dirAndFile[$k][4] = "error";
                        session(['install.error' => true]);
                    } else {
                        $dirAndFile[$k][2] = "不存在";
                        $dirAndFile[$k][1] = "不存在";
                        $dirAndFile[$k][4] = "error";
                        session(['install.error' => true]);
                    }
                }
            }
        }

        return $dirAndFile;
    }
}
